/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vpkmanager;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author jquick
 */
public class VpkManager {

    public VpkFile vpf;
    public String vpk_file;
    public final int directoryArchiveIndex = 0x7FFF;
        
    public VpkManager(String file) throws IOException {
        vpk_file = file;
        vpf = new VpkFile(file);
    }
    
    
    public void listFiles() {
        System.out.println("test");
        
        for (VpkNode ext : vpf.nodes)
            for (VpkNode path : ext.children)
                for (VpkNode file : path.children)
                    System.out.println(file.getFilePath());
    }
    
    public static void main(String args[]) throws IOException {
        String vpk_filez = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\dota 2 beta\\dota\\pak01_dir.vpk";
        VpkManager manager = new VpkManager(vpk_filez);
        //VpkNode node = manager.vpf.getFile("sound/vo/wisp/under_attack.wav");
        manager.removeFile("resource/ui/hud_actionpanel.res", ".");
    }
    
    public int removeFile(String file, String outDir) {
        VpkNode node = vpf.getFile(file);
        if (node != null) {
            try {
                removeFileNode(vpk_file, node);
                return 0;
            } catch (FileNotFoundException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return 1;
    }
    
    public byte[] convertInt(int in){
        byte[] bytes = new byte[4];
        for (int i = 0; i < 4; i++) {
            bytes[i] = (byte)(in >>> (i * 8));
        }
        return bytes;
    }
    
    public void removeFileNode(String vpkDirFileName, VpkNode node) throws FileNotFoundException, IOException {
        DataInputStream in = new DataInputStream(new FileInputStream(vpkDirFileName));
        DataOutputStream out = new DataOutputStream(new FileOutputStream(vpkDirFileName+".tmp"));

        byte[] buffer = new byte[1024];
        int amtToSkip = node.name.length() + 1 + 18 + node.preloadBytes;
        System.out.print(String.format("%d",amtToSkip));
        int i = 0;
        boolean done = false;
        int read;
        int index;

        //write headers
        out.write(convertInt(vpf.magic));
        out.write(convertInt(vpf.version));
        out.write(convertInt(vpf.treeLength - amtToSkip));
        in.skipBytes(12);
        index = node.index - 12;

        while ((read = in.read(buffer, 0, buffer.length)) > 0) {
            i += read;
            if (i >= index && done == false) {
                int stop = index - (i-read);
                int start = (stop + amtToSkip);
                
                out.write(buffer, 0, stop);   
                if (read < (stop+amtToSkip)) {
                    in.skipBytes((amtToSkip - read)+stop);
                } else {
                    out.write(buffer, start, (read-start));
                }
                done = true;
            } else {
                out.write(buffer, 0, read);
            }

        }
        out.close();
        in.close();
        //rename tmp file
        File orig = new File(vpkDirFileName);
        File bak = new File(vpkDirFileName+".orig");
        if (!bak.isFile()) {
            orig.renameTo(new File(vpkDirFileName+".orig")); //keep original
        } else {
            orig.delete();
        }
        new File(vpkDirFileName+".tmp").renameTo(orig);
    }
    
    public int extractFile(String file, String outDir) {
        VpkNode node = vpf.getFile(file);
        if (node != null) {
            try {
                extractNode(vpk_file, node, fixPath(outDir) + file);
                return 0;
            } catch (FileNotFoundException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return 1;
    }
    
    public String fixPath(String path) {
        //stupid path fix for linux vs windows
        if (path.indexOf("\\") == -1) {
            path = path + "/";
        } else {
            path = path + "\\";
        }
        return path;
    }
    
    public void extractNode(String vpkDirFileName, VpkNode node, String outDir) throws FileNotFoundException, IOException
    {

        InputStream in = getInputStream(vpkDirFileName, node, false);
        ensureDirectoryExists(node.getFileDirectory());
        DataOutputStream out = new DataOutputStream(new FileOutputStream(outDir + ".orig"));
        
        int read;
        if (node.preloadBytes > 0){
            InputStream inPreload = getInputStream(vpkDirFileName, node, true);
             //write preload data if any
            byte[] buffer = new byte[node.preloadData.length];
            read = inPreload.read(buffer, 0, buffer.length);
            out.write(buffer, 0, node.preloadData.length);
        }
        if (in != null) {
            byte[] buffer = new byte[1024];
            int amtToRead = (int)node.entryLength;     
            while ((read = in.read(buffer, 0, buffer.length)) > 0 && amtToRead > 0) {
                out.write(buffer, 0, Math.min(amtToRead, read));
                amtToRead -= read;
            }
        }
    }

    public void ensureDirectoryExists(String directory) {
        File f = new File(directory);
        if (!f.isDirectory()) {
           f.mkdirs();
        }
    }

    public InputStream getInputStream(String vpkDirFileName, VpkNode node, Boolean preload)
    {
        if (preload == true) {
            return new ByteArrayInputStream(node.preloadData);
        } else if (node.entryLength != 0) {
            String dataPakFilename = String.format("%03d", node.archiveIndex);
            dataPakFilename = vpkDirFileName.replace("_dir.vpk", "_" + dataPakFilename + ".vpk");
            FileInputStream fis;
            try {
                fis = new FileInputStream(dataPakFilename);
                fis.skip(node.entryOffset);
                return new DataInputStream(fis);
            } catch (FileNotFoundException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(VpkManager.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return null;
    }

}
